package tp.pr4.instructions;

import java.util.StringTokenizer;
import tp.pr4.NavigationModule;
import tp.pr4.RobotEngine;
import tp.pr4.instructions.exceptions.InstructionExecutionException;
import tp.pr4.instructions.exceptions.WrongInstructionFormatException;
import tp.pr4.items.ItemContainer;

/**
 * Its execution moves the robot from one place to the next one in the 
 * current direction. This instruction works if the user writes MOVE or MOVER
 * @author Alvaro Saez Hernando
 * @author Noel Clemente Montero 
 */
public class MoveInstruction implements Instruction {

	private static final String LINE_SEPARATOR = System.lineSeparator();
	private NavigationModule navigation;
	private RobotEngine robot;

	/**
	 * Default constructor.
	 */
	public MoveInstruction(){
		
	}
	
	/**
	 * Its execution moves the robot from one place to the next one in the 
	 * current direction. This instruction works if the user writes MOVE or MOVER
	 * @param cad text String to parse
	 * @return Instruction Reference to an instance of MoveInstruction
	 * @throws WrongInstructionFormatException When the String is not MOVE
	 */
	public Instruction parse(String cad) throws WrongInstructionFormatException {
		
		StringTokenizer st = new StringTokenizer(cad, " ");
		String word = st.nextToken().toUpperCase();
		
		if ((word.equals("MOVE")) || (word.equals("MOVER"))) {
			if (!st.hasMoreTokens())
				return new MoveInstruction();
			else
				throw new WrongInstructionFormatException("WALL·E says: I do not understand. Please repeat" + LINE_SEPARATOR);
		} 
		else
			throw new WrongInstructionFormatException("WALL·E says: I do not understand. Please repeat" + LINE_SEPARATOR);
	}

	/**
	 * Returns a description of the Instruction syntax. The string does not end 
	 * with the line separator. It is up to the caller adding it before printing.
	 * @return the command syntax MOVE|MOVER
	 */
	public String getHelp() {
		return "MOVE | MOVER" + LINE_SEPARATOR;
	}

	/**
	 * Set the execution context. The method receives the entire engine (engine, 
	 * navigation and the robot container) even though the actual implementation of execute() may not require it.
	 * @param engine The robot engine
	 * @param navigation The information about the game, i.e., the places, 
	 * current direction and current heading to navigate
	 * @param robotContainer The inventory of the robot
	 */
	public void configureContext(RobotEngine engine,NavigationModule navigation, ItemContainer robotContainer) {
		this.navigation = navigation;
		this.robot = engine;
	}

	/**
	 * Moves from the current place to the next place on the current Direction.
	 * An opened street must exist between both places to be moved
	 * @throws InstructionExecutionException When the robot cannot go to other place 
	 * (there is a wall, a closed street...)
	 */
	public void execute() throws InstructionExecutionException {
		if(robot.getFuel() <=0){
			robot.requestQuit();
			throw new InstructionExecutionException();
		}
		else{
			if(this.robot.getFuel() >= 5)
			{
				this.navigation.move();
				System.out.println("WALL·E says: Moving in direction "+this.navigation.getCurrentHeading());
				this.navigation.scanCurrentPlace();
				this.robot.addFuel(-5);
				System.out.print(LINE_SEPARATOR);
				this.robot.printRobotState();
				if(this.navigation.atSpaceship()){
					this.robot.requestQuit();
					System.out.println("WALL·E says: I am at my spaceship. Bye bye");
				}
			}
			else{
				throw new InstructionExecutionException("WALL·E says: Oh no! I have not enough power to move");
			}
		}
		

		
	}

}
